package com.icas.service;

import com.alibaba.fastjson.JSONObject;
import com.icas.entity.databaseentity.AllCourseEntity;
import com.icas.entity.databaseentity.AttendSheetEntity;
import com.icas.entity.databaseentity.StuAttend;
import com.icas.entity.resultentity.HistoryAttendEntity;
import com.icas.entity.resultentity.Result;
import com.icas.entity.resultentity.StuCourseHistoryAttendEntity;
import com.icas.enums.MsgResultEnum;
import com.icas.util.Constant;
import com.icas.util.TimeUtils;
import com.mongodb.BasicDBObject;
import com.mongodb.client.model.UpdateOptions;
import org.bson.BasicBSONObject;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author: tocchen
 * @Date: 2022/4/19 14:07
 * @Description
 **/
@Component
public class AttendService {

    @Autowired
    private MongoTemplate mongoTemplate;

    public static AttendService db;

    public static final AttendService defaultUserServer = new AttendService();

    @PostConstruct
    public void init() {
        db = this;
        db.mongoTemplate = this.mongoTemplate;
    }


    /**
     * 通过课程id，获取该课程的签到列表
     * @param courseId 课程id
     */
    public Result byCourseIdGetAttendList(String courseId){
        Query query = new Query();
        query.addCriteria(Criteria.where("courseId").is(courseId));
        query.fields().include("date","status");
        //  asc  desc
        query.with(Sort.by(Sort.Order.desc("date")));
        List<JSONObject> res = db.mongoTemplate.find(query,JSONObject.class, Constant.ATTEND_SHEET_TABLE_NAME);

        if (ObjectUtils.isEmpty(res)){
            return Result.error(MsgResultEnum.QUERY_FAILED);
        }
        ArrayList<HistoryAttendEntity> historyAttendEntities = new ArrayList<>();

        res.forEach(v->{
            String id = v.getString("_id");
            String date = TimeUtils.strToTimeStamp(v.getLong("date"));
            String status = v.getString("status");
            historyAttendEntities.add(HistoryAttendEntity.createEntity(id,date,status));
        });

        return historyAttendEntities.size()==0 ? Result.error(MsgResultEnum.QUERY_FAILED): Result.oK(historyAttendEntities);
    }

    /**
     * 通过签到表id，获取学生签到情况
     * @param sheetId 签到表id
     */
    public List<StuAttend> byAttendSheetIdGetStuList(String sheetId){
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(new ObjectId(sheetId)));
        query.fields().include("stuAttend").exclude("_id");
        AttendSheetEntity res = db.mongoTemplate.findOne(query,AttendSheetEntity.class,Constant.ATTEND_SHEET_TABLE_NAME);
        if (res == null ||res.getStuAttend() == null ){
            return null;
        }
        return res.getStuAttend();
    }

    /**
     * 修改学生在签到表中的状态信息
     * @param sheetId 签到表id
     * @param stuId 学生账号
     * @param newStatus 新状态
     */
    public void upDateStuStatus(String sheetId,String stuId,String newStatus) {
        // 拼接Set语句
        BasicDBObject update = new BasicDBObject();
        UpdateOptions updateOptions = new UpdateOptions();
        BasicBSONObject eleSetBson = new BasicBSONObject();
        eleSetBson.put("stuAttend.$[stuAttend].status", newStatus);
        update.put("$set", eleSetBson);

        // 拼接Filter参数
        List list = new ArrayList<>();
        BasicDBObject eleStuIdFilterBson = new BasicDBObject();
        eleStuIdFilterBson.put("stuAttend.stuId", stuId);
        list.add(eleStuIdFilterBson);
        updateOptions.arrayFilters(list);

        Criteria findIdCriteria = Criteria.where("_id").is(new ObjectId(sheetId));

        db.mongoTemplate.getCollection(Constant.ATTEND_SHEET_TABLE_NAME).updateOne(
                findIdCriteria.getCriteriaObject(),
                update,
                updateOptions
        );

    }

    /**
     * 更改签到表的状态 具体实现为 : "start" -> "end"
     * @param sheetId 签到表信息
     */
    public Boolean upDateAttendStatus(String sheetId){
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(new ObjectId(sheetId)));

        Update update = new Update();
        update.set("status","end");

        try{
            db.mongoTemplate.updateFirst(query, update, Constant.ATTEND_SHEET_TABLE_NAME);
            return Boolean.TRUE;
        }catch (Exception e){
            e.printStackTrace();
            return Boolean.FALSE;
        }

    }

    /**
     * 创建签到表
     * @param courseId 课程Id
     * @param classRoom 教室
     * @param longitude 经度
     * @param latitude 纬度
     */
    public Boolean createAttend(String courseId,String classRoom,String longitude,String latitude,Long validTime,String range){
        AllCourseEntity allCourseEntity = CourseService.defaultUserServer.byIdGetInfo(courseId);
        if (ObjectUtils.isEmpty(allCourseEntity)){
            return Boolean.FALSE;
        }
        AttendSheetEntity attendSheetEntity = new AttendSheetEntity();
        attendSheetEntity.setBasicInfo(allCourseEntity,Double.parseDouble(longitude),Double.parseDouble(latitude),classRoom,validTime,range);

        try{
            db.mongoTemplate.insert(attendSheetEntity,Constant.ATTEND_SHEET_TABLE_NAME);
            return Boolean.TRUE;
        }catch (Exception e){
            e.printStackTrace();
            return Boolean.FALSE;
        }
    }

    /**
     * TODO 目前没有需求的方法
     * @param courseId
     * @return
     */
    public JSONObject getAllStuHistoryAttend(String courseId){
        return null;
    }

    /**
     *
     * 查询学生在某个课程的签到历史
     * @param courseId 课程Id
     * @param stuId 学生账号
     * @return JSONObject
     */
    public List<StuCourseHistoryAttendEntity> getStuHistoryAttend(String courseId, String stuId){
        List<AggregationOperation> operations = new ArrayList<>();
        operations.add(Aggregation.match(Criteria.where("courseId").is(courseId)));
        operations.add(Aggregation.project("stuAttend", "course","status","validTime","date","location","range"));
        operations.add(Aggregation.unwind("stuAttend"));
        operations.add(Aggregation.match(Criteria.where("stuAttend.stuId").is(stuId)));
        operations.add(Aggregation.sort(Sort.Direction.DESC, "date"));

        Aggregation aggregation = Aggregation.newAggregation(operations);
        List<JSONObject> res = db.mongoTemplate.aggregate(aggregation, Constant.ATTEND_SHEET_TABLE_NAME, JSONObject.class).getMappedResults();

        List<StuCourseHistoryAttendEntity> stuHistory = new ArrayList<>();

        res.forEach(
                v ->{

                    Long dateLong = v.getLong("date");
                    Long validTime = v.getLong("validTime");
                    JSONObject stuAttend = v.getJSONObject("stuAttend");

                    Object location = v.get("location");

                    stuHistory.add(
                            new StuCourseHistoryAttendEntity(
                                    v.getString("_id"),
                                    TimeUtils.strToTimeStamp(dateLong),
                                    String.valueOf(validTime),
                                    v.getString("status"),
                                    stuAttend.getString("status"),
                                    location,
                                    v.getString("range")
                            )
                    );
                }
        );

        return stuHistory;
    }

}
